import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


public class ChomskyGrammar extends Grammar {
	
	
	protected ProductionFNC Axiom;
	protected Set<SymboleNonTerminaux> SymbolenonTerminaux;
	protected SymboleNonTerminaux SN;
	protected Alphabet alpha;

	
	/*TODO : un constructeur */
	
	public ChomskyGrammar(Alphabet alphabet, ProductionFNC prod, Set<SymboleNonTerminaux> SymbolenonTerminaux, SymboleNonTerminaux SN){
	
		this.alpha = alphabet;
	     this.Axiom = prod;
	       this.SymbolenonTerminaux= SymbolenonTerminaux;
	          this.SN= SN;
	}
		
		public ChomskyGrammar() {

			this.alpha = new Alphabet();
		     this.Axiom = new ProductionFNC();
		     this.SymbolenonTerminaux = new HashSet<SymboleNonTerminaux>();
		
	}

		public boolean accept(String mot){
		return analyseCYK(mot);
		}
		public boolean analyseCYK(String mot){
		
			SymboleTerminaux a;
		    ArrayList<Symbole> prod = new ArrayList<Symbole>();
	        int n = mot.length();
		    Cellule[][] cellule = new Cellule[n][n];
		
		    for (int i = 1; i <= n; i++) {
					prod.clear();
					a = new SymboleTerminaux(mot.charAt(i));
					prod.add(a);
				
				if (getP().contains(a))
						cellule[1][i].add(a);
		}
		
		    for (int l = 2; l < n; l++) {
		
			for (int i = 1; i <= n - l + 1; i++) {
		
			for (int m = 1; m < l; m++) {
		
			for (Regle r : this.getP()) {
		SymboleNonTerminaux X = r.getGauche();
		List<Symbole> nonTerms = r.getDroite();
		
		for (Symbole AB : nonTerms) {
	
			if (((Regle) getP()).getDroite().contains(nonTerms)
		&& cellule[m][i].contains(AB)
		&& cellule[l - m][i + m].contains(AB))
		cellule[l][i].add(X);
		                           }
		                           }
		                           }
		                                      }
		}
		return (cellule[n][1].contains(this.getS()));
		}

		
		
		
		/**
		* Add a symbol to the alphabet of the chomsky grammar
		*
		* @param s
		* the symbol to add
		*/
		public void addSymbolToAlphabet(Symbole SS) {
		      this.alpha.add(SS);
		}
		/**
		* Add a non terminal symbol to the chomsky grammar
		*
		* @param t
		* the non terminal symbol to add
		*/
		public void addNonTerminalSymbol(SymboleNonTerminaux SN) {
		this.SymbolenonTerminaux.add(SN);
		
}

		public void setAxiom(SymboleNonTerminaux S) {
			if (!this.SymbolenonTerminaux.contains(S))
			this.SymbolenonTerminaux.add(S);
			this.SN = S;
			}
			/**
			* Add the t -> f production to the chomsky grammar
			*
			* @param t
			* the left non terminal symbol
			* @param f
			* the right terminal symbol
			*/
			public void addProduction(SymboleNonTerminaux t, Symbole f) {
			this.Axiom.add(t, f);
			}
			/**
			* add the t -> t1 t2 production to the chomsky grammar
			*
			* @param t
			* the left non terminal symbol
			* @param t1
			* the first right non terminal symbol
			* @param t2
			* the second right non terminal symbol
			*/
			public void addProduction(SymboleNonTerminaux t, SymboleNonTerminaux t1, SymboleNonTerminaux t2) {
			this.Axiom.add(t, t1, t2);
			}
		
}